package com.simon.train.business.service;

import com.simon.train.business.domain.ConfirmOrder;
import com.simon.train.business.domain.DailyTrainSeat;
import com.simon.train.business.domain.DailyTrainTicket;
import com.simon.train.business.dto.ConfirmOrderTicketDto;
import com.simon.train.business.enums.ConfirmOrderStatusEnum;
import com.simon.train.business.feign.MemberFeign;
import com.simon.train.business.mapper.ConfirmOrderMapper;
import com.simon.train.business.mapper.DailyTrainSeatMapper;
import com.simon.train.business.mapper.cust.DailyTrainTicketMapperCust;
import com.simon.train.common.Result.Result;
import com.simon.train.common.context.LoginMemberContext;
import com.simon.train.common.dto.MemberTicketDto;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

@Service
public class AfterConfirmTicketService {

    private static final Logger LOG = LoggerFactory.getLogger(AfterConfirmTicketService.class);

    @Resource
    private DailyTrainSeatMapper dailyTrainSeatMapper;

    @Resource
    private DailyTrainTicketMapperCust dailyTrainTicketMapperCust;

    @Resource
    private MemberFeign memberFeign;

    @Resource
    private ConfirmOrderMapper confirmOrderMapper;

    /**
     * 事务处理
     * 1.座位表的售卖情况
     * 2.余票详情表的余票数量
     * 3.为会员增加购票记录（目前还没添加这个表）
     * 4.更新 确认订单表 对应的状态为 成功
     *
     * 由于需要事务处理 必须在不同的类 这里我们重新定义一个service进行事务处理
     */
    @Transactional
    public void AfterConfirmTicket(DailyTrainTicket dailyTrainTicket, List<DailyTrainSeat> FinalSeatList, List<ConfirmOrderTicketDto> tickets, ConfirmOrder confirmOrder){
        //更新座位表的售卖情况
        for(int j = 0; j < FinalSeatList.size(); j++){
            DailyTrainSeat TempSeat = new DailyTrainSeat();
            DailyTrainSeat dailyTrainSeat = FinalSeatList.get(j);
            TempSeat.setId(dailyTrainSeat.getId());
            TempSeat.setSell(dailyTrainSeat.getSell());
            TempSeat.setUpdateTime(new Date());
            dailyTrainSeatMapper.updateByPrimaryKeySelective(TempSeat);

            /**
             * 余票详情表的余票数量进行修改 需要将所有有影响的余票都进行处理
             * 假设10个站 本次购买4-7站
             * 原售:0010 000 01
             * 购买:0000 111 00
             * 新售:0010 111 01
             * 影响:XXX1 111 1X
             * 也就是说影响的库存是:本次选座之前没有卖过票的+和本次购买的区间有交集的区间
             *
             * Integer startIndex = 4;
             * Integer endIndex = 7;
             * Integer minStartIndex = startIndex向前碰到的最后一个0;
             * Integer maxStartIndex = endIndex - 1;
             * Integer minEndIndex = startIndex + 1;
             * Integer maxEndIndex = endIndex向后碰到的最后一个0;
             */
            Integer startIndex = dailyTrainTicket.getStartIndex();
            Integer endIndex = dailyTrainTicket.getEndIndex();
            Integer maxStartIndex = endIndex - 1;
            Integer minEndIndex = startIndex + 1;
            Integer minStartIndex = 0; //当i=0的时候仍然不为'1'的时候 i下一次就变成-1了 那么实际上就可以设置minStartIndex为0 所以我们直接设置初始值为0
            char[] sellArray = TempSeat.getSell().toCharArray();
            for(int i = startIndex - 1; i >= 0; i--){
                if(sellArray[i] == '1'){
                    minStartIndex = i + 1;
                    break;
                }
            }
            /**
             * 需要注意的是 比如购买4-7站 对于0010 111 01来说 下标从0开始 则核心控制的下标为4，5，6 并没有7
             * 所以endIndex本质上是不能映射到sell数组里的 所以这个for循环的i不能从endIndex+1开始 而应该直接从endIndex开始
             * 同时当匹配到为1的情况时 也不用i-1去赋值 因为maxEndIndex本身也不映射位置 调试可以确定最终边界
             *
             * maxEndIndex初始化而言 比如一共有10站 最大的EndIndex也就是最后一站 但是其应该有的索引是9 正好等于TempSeat.getSell()的长度 所以不用-1
             */
            Integer maxEndIndex = TempSeat.getSell().length();
            for(int i = endIndex; i < sellArray.length; i++){
                if(sellArray[i] == '1'){
                    maxEndIndex = i;
                    break;
                }
            }

            LOG.info("Sell:{}, startIndex:{}, minStartIndex:{}, maxStartIndex:{}, endIndex:{}, minEndIndex:{}, maxEndIndex:{}",
                    TempSeat.getSell(),startIndex, minStartIndex, maxStartIndex, endIndex, minEndIndex, maxEndIndex);

            dailyTrainTicketMapperCust.updateCountBySell(
                    dailyTrainTicket.getDate(),
                    dailyTrainTicket.getTrainCode(),
                    dailyTrainSeat.getSeatType(),
                    minStartIndex,
                    maxStartIndex,
                    minEndIndex,
                    maxEndIndex);

            MemberTicketDto memberTicketDto = new MemberTicketDto();
            memberTicketDto.setMemberId(LoginMemberContext.getId());
            memberTicketDto.setPassengerId(tickets.get(j).getPassengerId());
            memberTicketDto.setPassengerName(tickets.get(j).getPassengerName());
            memberTicketDto.setTrainDate(dailyTrainTicket.getDate());
            memberTicketDto.setTrainCode(dailyTrainTicket.getTrainCode());
            memberTicketDto.setCarriageIndex(dailyTrainSeat.getCarriageIndex());
            memberTicketDto.setSeatRow(dailyTrainSeat.getRow());
            memberTicketDto.setSeatCol(dailyTrainSeat.getCol());
            memberTicketDto.setStartStation(dailyTrainTicket.getStart());
            memberTicketDto.setStartTime(dailyTrainTicket.getStartTime());
            memberTicketDto.setEndStation(dailyTrainTicket.getEnd());
            memberTicketDto.setEndTime(dailyTrainTicket.getEndTime());
            memberTicketDto.setSeatType(dailyTrainSeat.getSeatType());
            Result<Object> result = memberFeign.save(memberTicketDto);
            LOG.info("通过feign调用member提供的接口写入用户买票的数据，返回：{}", result);

            //更新 确认订单表 对应的状态为 成功
            ConfirmOrder confirmOrderForUpdate = new ConfirmOrder();
            confirmOrderForUpdate.setId(confirmOrder.getId());
            confirmOrderForUpdate.setUpdateTime(new Date());
            confirmOrderForUpdate.setStatus(ConfirmOrderStatusEnum.SUCCESS.getCode());
            confirmOrderMapper.updateByPrimaryKeySelective(confirmOrderForUpdate);

        }




    }
}
